package org.example;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipService {
    private final String srcFilePath;
    private final String targetFilePath;
    private final Set<File> fileSet;
    private String zipName;

    public ZipService(String srcFilePath, String targetFilePath) {
        this.srcFilePath = srcFilePath;
        this.targetFilePath = targetFilePath;
        fileSet = new TreeSet<>((o1, o2) -> (int) (o2.lastModified() - o1.lastModified()));
        setZipName("archiveZip_%s.zip");
    }

    public static void main(String[] args) {
        LocalDate target = LocalDate.of(2023, 5, 6);
        String filePath = System.getProperty("user.home");
        System.out.println(filePath);
        LocalDate now = LocalDate.now();
        long between = ChronoUnit.DAYS.between(target, now);
        System.out.println(between);
        long epochMilliTarget = LocalDateTime.now().plusDays(-between).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        long epochMilliNow = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        ZipService zipService = new ZipService(filePath, filePath + File.separator + "archive");
        zipService.archiveFiles(epochMilliNow - epochMilliTarget);
    }

    public void archiveFiles(long milliSeconds) {
        File[] files = new File(srcFilePath).listFiles();
        if (files == null || files.length == 0) {
            return;
        }
        long now = Instant.now().toEpochMilli();
        List<File> collect = Arrays.stream(files).filter(e -> now - e.lastModified() > milliSeconds).toList();
        fileSet.addAll(collect);
        System.out.println("need to archive files size=" + fileSet.size());
        try {
            archive();
            afterArchive();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void afterArchive() {
        if (fileSet != null && !fileSet.isEmpty()) {
            fileSet.forEach(File::delete);
        }
    }

    private void archive() throws IOException {
        if (fileSet.isEmpty()) {
            return;
        }
        String zipNameFormat = getZipName();
        File path = new File(targetFilePath);
        File zip = new File(targetFilePath + File.separator + zipNameFormat);
        if (!path.exists() && !path.mkdirs()) {
            throw new RuntimeException("create path fail!");
        }
        if (!zip.exists() && !zip.createNewFile()) {
            throw new RuntimeException("create zip file fail!");
        }
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip))) {
            for (File file : fileSet) {
                zos.putNextEntry(new ZipEntry(file.getName()));
                try (FileInputStream fis = new FileInputStream(file)) {
                    int len;
                    byte[] buffer = new byte[1024];
                    while ((len = fis.read(buffer)) != -1) {
                        zos.write(buffer, 0, len);
                    }
                    zos.closeEntry();
                }
            }
        }
    }

    public String getZipName() {
        return String.format(zipName, DateTimeFormatter.ofPattern("yyMMddHHmmss").format(LocalDateTime.now()));
    }

    public void setZipName(String zipName) {
        this.zipName = zipName;
    }
}
